﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using LockCrypt.Converters;
using LockCrypt.Properties;
using Microsoft.Win32;
using LockCrypt.Core;

namespace Lime49.UI {
    /// <summary>
    /// A label, textbox and browse button for choosing files to open/save.
    /// </summary>
    public partial class FilePicker : UserControl {
        private FileDialog _dlg;

        public event EventHandler PathChanged;

        public static DependencyProperty SelectedPathProperty = DependencyProperty.Register("SelectedPath", typeof(string), typeof(FilePicker), new PropertyMetadata(string.Empty, new PropertyChangedCallback(SelectedPath_Changed)));
        private static void SelectedPath_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            FilePicker ctl = d as FilePicker;
            if(ctl.PathChanged != null) {
                ctl.PathChanged(ctl, EventArgs.Empty);
            }
        }

        /// <summary>
        /// Gets or sets the selected path.
        /// </summary>
        /// <value>The selected path.</value>
        public string SelectedPath {
            get { return Convert.ToString(base.GetValue(SelectedPathProperty)); }
            set { base.SetValue(SelectedPathProperty, value); }
        }

        public static DependencyProperty PathHistoryKeyProperty = DependencyProperty.Register("PathHistoryKey", typeof(string), typeof(FilePicker), new PropertyMetadata(string.Empty, new PropertyChangedCallback(PathHistoryKey_Changed)));
        private static void PathHistoryKey_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            FilePicker ctl = d as FilePicker;
            if(string.IsNullOrEmpty(ctl.PathHistoryKey)) {
                ctl.txtPath.Visibility = Visibility.Visible;
                ctl.cboPath.Visibility = Visibility.Collapsed;
                FocusManager.SetFocusedElement(ctl, ctl.txtPath);
            } else {
                ctl.txtPath.Visibility = Visibility.Collapsed;
                ctl.cboPath.Visibility = Visibility.Visible;
                FocusManager.SetFocusedElement(ctl, ctl.cboPath);
                Binding bndFileHistory = new Binding() {
                    UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
                    Mode = BindingMode.TwoWay,
                    Converter = new StringToListConverter(),
                    ConverterParameter = "|"
                };
                bndFileHistory.Path = new PropertyPath("Default[" + ctl.PathHistoryKey + "]");
                ctl.cboPath.SetBinding(ComboBox.ItemsSourceProperty, bndFileHistory);
            }
        }
        /// <summary>
        /// Gets or sets the settings key used to store file history.
        /// </summary>
        /// <value>The settings key used to store file history.</value>
        public string PathHistoryKey {
            get { return Convert.ToString(base.GetValue(PathHistoryKeyProperty)); }
            set { base.SetValue(PathHistoryKeyProperty, value); }
        }

        #region File Chooser
        public static DependencyProperty IsSaveDialogProperty = DependencyProperty.Register("IsSaveDialog", typeof(bool), typeof(FilePicker), new PropertyMetadata(true, new PropertyChangedCallback(IsSaveDialog_Changed)));
        /// <summary>
        /// Gets or sets whether a SaveFileDialog or an OpenFileDialog should be shown when browsing for a file. Default is <c>true</c>.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if a SaveFileDialog should be shown to browse for a file path, <c>false</c> to show an OpenFileDialog.
        /// </value>
        public bool IsSaveDialog {
            get { return System.Convert.ToBoolean(base.GetValue(IsSaveDialogProperty)); }
            set { base.SetValue(IsSaveDialogProperty, value); }
        }
        private static void IsSaveDialog_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            FilePicker ctl = d as FilePicker;
            FileDialog newDialog;
            if(ctl.IsSaveDialog) {
                newDialog = new SaveFileDialog() {
                    OverwritePrompt = true,
                    AddExtension = true
                };
            } else {
                newDialog = new OpenFileDialog() {
                    CheckPathExists = true,
                    Multiselect = false
                };
            }
            newDialog.Title = ctl.DialogTitle;
            newDialog.Filter = ctl.FilterString;
            newDialog.FilterIndex = ctl.FilterIndex;
            newDialog.DefaultExt = ctl.DefaultExtension;
            ctl._dlg = newDialog;
        }

        /// <summary>
        /// Gets or sets the filter string that determines what types of files are displayed from either the Microsoft.Win32.OpenFileDialog or Microsoft.Win32.SaveFileDialog
        /// </summary>
        /// <value>The filter string.</value>
        public string FilterString {
            get { return _dlg.Filter; }
            set { _dlg.Filter = value; }
        }

        /// <summary>
        /// Gets or sets the index of the selected filter (starting at 1).
        /// </summary>
        /// <value>The index of the selected filter.</value>
        public int FilterIndex {
            get { return _dlg.FilterIndex; }
            set { _dlg.FilterIndex = value; }
        }

        /// <summary>
        /// Gets or sets a value that specifies the default extension string to use to filter the list of files that are displayed.
        /// </summary>
        /// <value>The default extension.</value>
        public string DefaultExtension {
            get { return _dlg.DefaultExt; }
            set { _dlg.DefaultExt = value; }
        }

        /// <summary>
        /// Gets or sets the title of the open/save dialog.
        /// </summary>
        /// <value>The title of the open/save dialog.</value>
        public string DialogTitle {
            get { return _dlg.Title; }
            set { _dlg.Title = value; }
        }
        #endregion

        public static DependencyProperty LabelTextProperty = DependencyProperty.Register("LabelText", typeof(string), typeof(FilePicker), new PropertyMetadata(string.Empty));
        /// <summary>
        /// Gets or sets the text on the TextBox label.
        /// </summary>
        /// <value>The label text.</value>
        public string LabelText {
            get { return Convert.ToString(base.GetValue(LabelTextProperty)); }
            set { base.SetValue(LabelTextProperty, value); }
        }

        public FilePicker() {
            _dlg = new SaveFileDialog();
            InitializeComponent();
        }


        /// <summary>
        /// Shows a dialog to select a file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void BrowseForDBFile(object sender, RoutedEventArgs e) {
            string[] items = new string[0];
            string history = string.Empty;
            if(!string.IsNullOrEmpty(PathHistoryKey)) {
                history = Settings.Default[PathHistoryKey] as string;
                if(history == null) {
                    // settings value is not a string
                    return;
                }
                items = history.Split(new[] {'|'}, StringSplitOptions.RemoveEmptyEntries);
                try {
                    if(items.Length > 0) {
                        string mostRecentFile = items.Last();
                        if(File.Exists(mostRecentFile)) {
                            _dlg.FileName = mostRecentFile;
                        }
                    } else {
                        //SelectedFile = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "lockcrypt" + dlgSave.DefaultExt);
                    }
                } catch {
                }
            }
            if(!string.IsNullOrEmpty(SelectedPath)) {
                try {
                    _dlg.FileName = SelectedPath;
                    _dlg.InitialDirectory = System.IO.Path.GetDirectoryName(SelectedPath);
                } catch {
                }
            }
            if(_dlg.ShowDialog() == true) {
                if(!string.IsNullOrEmpty(PathHistoryKey) && !string.IsNullOrEmpty(_dlg.FileName) && !items.Contains(_dlg.FileName)) {
                    Settings.Default[PathHistoryKey] = string.Format("{0}|{1}", history, _dlg.FileName);
                    Settings.Default.Save();
                    cboPath.GetBindingExpression(ComboBox.ItemsSourceProperty).UpdateTarget();
                }
                SelectedPath = _dlg.FileName;
            }
        }

        /// <summary>
        /// Fires the PathChanged event when the path changes.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void cboPath_Changed(object sender, RoutedEventArgs e) {
            if(PathChanged != null)
                PathChanged(this, EventArgs.Empty);
        }

        /// <summary>
        /// Checks the validity of the selected the path.
        /// </summary>
        /// <returns></returns>
        public bool ValidatePath() {
            bool valid = true;
            try {
                //throws an exception if invalid path
                System.IO.Path.GetFileName(SelectedPath);
            } catch {
                DialogBox.ShowAlert(Window.GetWindow(this), I18nUtils.GetString("Errors", "InvalidFilename"), I18nUtils.GetString("Errors", "Error"));
                if(string.IsNullOrEmpty(PathHistoryKey)) {
                    txtPath.Focus();
                } else {
                    cboPath.Focus();
                }
                valid = false;
            }
            return valid;
        }
    }
}
